package com.atguigu.gulimall.product.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Author LiDeJie
 * @Create 2024/1/21 14:08
 * @Version 1.0
 */
public class CompletableFutureDemo {
    
    static Logger logger = LoggerFactory.getLogger(CompletableFutureDemo.class);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> completableFuture01 = CompletableFuture.supplyAsync(() -> {
            logger.info("completableFuture01 com in ThreadName: {}", Thread.currentThread().getName());
            Integer result = 10 / 5;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result;
        }, MyThreadPoolExecutor.threadPoolExecutor);
    
        CompletableFuture<Integer> completableFuture02 = CompletableFuture.supplyAsync(() -> {
            logger.info("completableFuture02 com in ThreadName: {}", Thread.currentThread().getName());
            Integer result = 10 / 2;
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result;
        }, MyThreadPoolExecutor.threadPoolExecutor);
    
        //组合两个异步任务只要有一个异步任务完成以后，拿到异步任务的结果进行处理在进行返回
//        CompletableFuture<Integer> applyToEither = completableFuture01.applyToEither(completableFuture02, result -> result + 2);
//        logger.info("applyToEither result: {}", applyToEither.get());
    
        //拿到前两个异步任务的执行并进行处理没有返回值
//        completableFuture01.acceptEither(completableFuture02, result -> logger.info("last two future task result: {}", result));
        //等待前两次异步任务执行完毕，不需要前两次的异步任务结果，开启一个新的线程进行处理任务并且没有返回值
        completableFuture01.runAfterEither(completableFuture02, () -> {
            logger.info("runAfterEither");
        });
        
    
        logger.info("main ThreadName: {} execute finish", Thread.currentThread().getName());
    }
    
    private static void CompletableFutureAPIDemo04() throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> completableFuture01 = CompletableFuture.supplyAsync(() -> {
            logger.info("completableFuture01 com in ThreadName: {}", Thread.currentThread().getName());
            Integer result = 10 / 5;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result;
        }, MyThreadPoolExecutor.threadPoolExecutor);
        
        CompletableFuture<Integer> completableFuture02 = CompletableFuture.supplyAsync(() -> {
            logger.info("completableFuture02 com in ThreadName: {}", Thread.currentThread().getName());
            Integer result = 10 / 2;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result;
        }, MyThreadPoolExecutor.threadPoolExecutor);
        
        //两个异步任务进行合并操作，有返回值
        /*CompletableFuture<Integer> thenCombine = completableFuture01.thenCombine(completableFuture02, (f1, f2) -> {
            logger.info("completableFuture01.thenCombine.completableFuture02: {} , f1: {}, f2: {}", completableFuture02, f1, f2);
            return f1 + f2;
        });*/
        /*Integer result = thenCombine.get();
        logger.info("combine f1 f2 result: {}", result);*/
        
        //组合两个异步任务，没有返回值
        /*CompletableFuture<Void> thenAcceptBoth = completableFuture01.thenAcceptBoth(completableFuture02, (f1, f2) -> {
            logger.info("f1: {}, f2: {}", f1, f2);
        });
        thenAcceptBoth.get();*/
        
        CompletableFuture<Void> runAfterBoth = completableFuture01.runAfterBoth(completableFuture02, () -> {
            logger.info("runAfterBoth 组合两个异步任务执行完毕并开启一个新的任务，没有返回结果");
        });
        
        //allOf 阻塞式等待：等待所有异步任务完成
        //anyOf 阻塞式等待：只要有一个异步任务完成以后就可以
        CompletableFuture<Void> allOf = CompletableFuture.allOf(completableFuture01, completableFuture02, runAfterBoth);
        allOf.get();
    }
    
    private static void CompletableFutureAPIDemo03() {
        CompletableFuture.supplyAsync(() -> {
            logger.info("supplyAsync com in ThreadName: {}", Thread.currentThread().getName());
            Integer result = 10 / 5;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result;
        }, MyThreadPoolExecutor.threadPoolExecutor).thenRunAsync(() -> {
            //thenRunAsync：默认启动一个线程任务，执行新的任务不需要上一次的异步任务结果
            //如果需要感知上一步的异步任务则使用：thenAccept 接收上一个异步任务的结果，无返回值
            //thenSupply 接收上一个异步任务执行的结果，并再次做处理并返回新的异步任务结果
            logger.info("thenRunAsync com in ThreadName: {}", Thread.currentThread().getName());
        }, MyThreadPoolExecutor.threadPoolExecutor);
    }
    
    private static void completableFutureAPIDemo02() throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            logger.info("supplyAsync com in ThreadName" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        
            int result = 10 / 0;
            logger.info("task execute finish , resp: {}", result);
            return result;
            //(BiFunction<? super T, Throwable, ? extends U> fn)
            //Handle：可以传入两个参数一个为上一个异步任务的执行结果、异常、有返回
            //whenComplete: 没有返回
        }).handle((result, exception) -> {
            if (exception == null) {
                logger.info("last future task execute result: {}", result);
            } else {
                logger.error("last future task exception: {}", exception.getMessage());
                exception.printStackTrace();
                return -1;
            }
            return -1;
        });
        if (future.get() == -1) {
            logger.info("execute exception logic");
        }
    }
    
    private static void CompletableFutureApiDemo01() throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            logger.info("supplyAsync com in ThreadName" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        
            int result = 10 / 0;
            logger.info("task execute finish , resp: {}", result);
            return result;
            //BiConsumer<? super T, ? super Throwable> action)
            //whenComplete：拿到上一次异步执行的结果和异常做处理，没有返回值
        }).whenComplete((result, exception) -> {
            if (exception == null) {
                logger.info("last Future execute result: {}, exception: {}", result, exception);
            }else {
                logger.error("execute exception hande");
            }
        }).exceptionally(exception -> {
            exception.printStackTrace();
            logger.error("future task exception errorMsg: {}", exception.getMessage());
            return -1;
        });
        //get() 一经调用就会阻塞等到上面异步任务执行完毕
        if (future.get() == -1) {
            logger.error("hande exception magic");
        }
    }
}
